package com.bwie.task;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bwie.domain.Prod;
import com.bwie.es.EsProdVo;
import com.bwie.mapper.ProdMapper;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @BelongsProject: E-Commerce-Month-01
 * @BelongsPackage: com.bwie.task
 * @Author: asus
 * @CreateTime: 2025-10-30  19:59
 * @Description:
 * @Version: 1.0
 * 全量/增量策略
 *  1、首次同步 （redis 中没有同步时间） -> 全量同步
 *  2、后续同步 ->以上同步时间为起点 增量同步
 *  调度频率 每分钟一次 ( corn = "0 * * * * ?")
 */
@Component
public class EsTask {

    @Autowired ElasticsearchRestTemplate elasticsearchRestTemplate; // ES 操作模板
    @Autowired StringRedisTemplate redisTemplate; //Redis 缓存
    @Autowired ProdMapper prodMapper; // 商品 mapper


    /* Redis 中保存最近一次的同步时间的 key */
    public static final String KEY_TIME = "prod-data-to-es";

    /**
     * @description: 每分钟触发一次同步
     * @author: Zero
     * @date: 2025/10/31 14:04
     * @param: []
     * @return: void
     **/
    @Scheduled(cron = "0 * * * * ?")
    public void prodDataToEs(){
        // 打印日志
        System.out.println("[Es Prod同步任务] 开始同步商品数据，时间："+DateUtil.now());

        /* 1、确保索引存在，不存在则创建索引 + 映射 */
        IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(EsProdVo.class);
        if (!indexOperations.exists()){
            // 创建索引
            indexOperations.create();
            // 创建映射
            Document mapping = indexOperations.createMapping();
            indexOperations.putMapping(mapping);
            System.out.println("[Es Prod同步任务] 索引不存在，已自动创建索引并映射");
        }

        /* 2、构建超大分页对象 */
        Page<Prod> prodPage = new Page<>(1, 99999);
        /* 3、记录 ”本次同步时间“——在任务最后写回 Redis */
        String now = DateUtil.now();

        /* 4、判断是否为首次同步 true 全量 false 增量 */
        if(!redisTemplate.hasKey(KEY_TIME)){
            // 4.1 全量同步：
            Page<Prod> page = prodMapper.selectProdListByPage(prodPage,null,null);
            System.out.println("[Es Prod同步任务] 首次同步任务查询到"+page.getRecords().size()+"条数据");
            this.syncListToEs(page.getRecords());
        }else {
            // 4.2 增量同步： 从redis中获取上次同步时间
            String redisKeyTime = redisTemplate.opsForValue().get(KEY_TIME);
            Page<Prod> page = prodMapper.selectProdListByPage(prodPage, null, redisKeyTime);
            System.out.println("[Es Prod同步任务] 增量同步：上次同步时间："+redisKeyTime+",本次同步："+page.getRecords().size()+"条变更商品");
            this.syncListToEs(page.getRecords());
        }
        /* 5、同步时间 KEY_TIME 过期时间 30 分钟，防止数据常驻 */
        redisTemplate.opsForValue().set(KEY_TIME,now,30,TimeUnit.MINUTES);
        System.out.println("[Es Prod同步任务]同步商品数据到 ES 结束,时间："+DateUtil.now());
    }
    /**
     * @description: 将 List<Prod>批量转换为 List<EsProdVo>
     * @author: Zero
     * @date: 2025/10/31 14:37
     * @param: [prodList]
     * @return: void
     **/
    public void syncListToEs(List<Prod> prodList) {
        // 空保护
        if (prodList == null || prodList.isEmpty()) {
            System.out.println("[Es Prod同步任务] 带同步列表为空，跳过");
            return;
        }
        /* 1、将 Prod -> EsProdVo (使用 stream 流 拷贝)*/
        for (Prod tbProd:prodList){
            EsProdVo esProdVo=new EsProdVo();
            BeanUtil.copyProperties(tbProd,esProdVo);
            /* 2、循环写入 ES */
            elasticsearchRestTemplate.save(esProdVo);
        }
        System.out.println("[Es Prod同步任务]已成功写入"+prodList.size()+"条数据");
    }




}
